home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 49
/
Amiga Format CD49 (2000-01-17)(Future Publishing)(GB)(Track 1 of 3)[!][issue 2000-02].iso
/
-in_the_mag-
/
program_perfection
/
gui
/
af_scroller.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-12-08
|
16KB
|
509 lines
/*
* af_scroller.c
*
* Modified from ClassFree scoller.gadget
* (Needs some tidying up, yet. . .)
*
* But it now supports relativity and can be put in borders :)
*
* $Id :$
* $Log:$
*
*/
#include "defs.h"
#include <intuition/intuition.h>
#include <intuition/classes.h>
#include <intuition/icclass.h>
#include <intuition/gadgetclass.h>
#include <intuition/imageclass.h>
#include <proto/dos.h>
#include <proto/intuition.h>
#include <clib/alib_protos.h>
#include "boopsi_misc.h"
#include "af_scroller.h"
#include "af_button.h"
#define THISCLASS_ID NULL
#define SUPERCLASS_ID GADGETCLASS
#define SUPERCLASS_PTR NULL
#define GADGET_BORDER_FLAGS ( GACT_RIGHTBORDER | GACT_LEFTBORDER | GACT_TOPBORDER | GACT_BOTTOMBORDER )
#define PROP_ID 0L
#define DECBTN_ID 1L
#define INCBTN_ID 2L
/*
* Private class types
*/
struct InstanceData
{
Object *act;
struct Gadget *prop,*decbtn,*incbtn;
struct Image *dec_image;
struct Image *inc_image;
};
/*
* Private data
*/
static Class *class_base;
static ULONG SAVEDS dispatcher( REG(a0) Class *cl, REG(a2) Object *o, REG(a1) Msg msg );
static ULONG new_method( Class *cl, Object *o, struct opSet *msg );
static ULONG dispose_method( Class *cl, Object *o );
static ULONG set_method( Class *cl, Object *o, struct opSet *msg );
static ULONG update_method( Class *cl, Object *o, Msg msg );
static ULONG hittest_method( Class *cl, Object *o, Msg msg );
static ULONG goactive_method( Class *cl, Object *o, Msg msg );
static ULONG handleinput_method( Class *cl, Object *o, Msg msg );
static ULONG goinactive_method( Class *cl, Object *o, Msg msg );
static ULONG render_method( Class *cl, Object *o, Msg msg );
static ULONG layout_method( Class *cl,Object *o, Msg msg );
static VOID position_gadgets( struct Gadget *scr, struct InstanceData *data, ULONG freedom );
static VOID set_gadget_position( struct Gadget *source, struct Gadget *dest, UWORD x_offset, UWORD y_offset );
static VOID set_gadget_size( struct Gadget *source, struct Gadget *dest, UWORD x_offset, UWORD y_offset );
static BOOL hit_test_gadget( struct Gadget *gad, struct Gadget *rel_gad, struct GadgetInfo *gi, WORD x, WORD y );
/*
* Public functions
*/
Class
*AFSCROLLER_GetClass(VOID)
{
return class_base;
}
VOID
_INIT_7_AFSCROLLER_InitClass( VOID )
{
if( class_base = MakeClass( THISCLASS_ID, SUPERCLASS_ID, SUPERCLASS_PTR, sizeof(struct InstanceData), 0L ) )
{
class_base->cl_Dispatcher.h_Entry = (ULONG (*)()) dispatcher;
return;
}
else
exit (20L);
}
VOID
_EXIT_7_AFSCROLLER_RemoveClass( VOID )
{
if( class_base )
FreeClass( class_base );
}
static ULONG SAVEDS
dispatcher( REG(a0) Class *cl, REG(a2) Object *o, REG(a1) Msg msg )
{
switch(msg->MethodID)
{
case OM_NEW: return( new_method( cl, o, (struct opSet *) msg ) );
case OM_DISPOSE: return( dispose_method( cl, o ) );
case OM_SET: return( set_method( cl, o, (struct opSet *) msg ) );
case OM_UPDATE: return( update_method( cl, o, msg ) );
case GM_HITTEST: return( hittest_method( cl, o, msg ) );
case GM_GOACTIVE:
case GM_HANDLEINPUT: return( handleinput_method( cl, o, msg ) );
case GM_GOINACTIVE: return( goinactive_method( cl, o, msg ) );
case GM_RENDER: return( render_method( cl, o, msg ) );
case GM_LAYOUT: return( layout_method( cl, o, msg ) );
default: return( DoSuperMethodA(cl,o,msg) );
}
}
static ULONG
new_method( Class *cl, Object *o, struct opSet *msg )
{
struct TagItem *attrs = msg->ops_AttrList;
struct Gadget *scr;
struct DrawInfo *dri;
WORD oldfill;
if( scr = (struct Gadget *) DoSuperMethodA( cl, o, (Msg) msg ) )
{
if( !( dri = (struct DrawInfo *) GetTagData( GA_DrawInfo,NULL, attrs ) ) )
{
DoSuperMethod( (Class *)o, (Object *) scr, OM_DISPOSE );
}
else
{
ULONG size = GetTagData( SYSIA_Size, SYSISIZE_MEDRES, attrs );
ULONG fdm = GetTagData( PGA_Freedom, FREEVERT, attrs );
ULONG total = GetTagData( PGA_Total, 1, attrs );
ULONG visible = GetTagData( PGA_Visible, 1, attrs );
ULONG top = GetTagData( PGA_Top, 0, attrs );
struct InstanceData *data = INST_DATA( cl ,scr );
/* Change fill color */
if( !( scr->Activation & GADGET_BORDER_FLAGS ) )
{
oldfill = dri->dri_Pens[ FILLPEN ];
dri->dri_Pens[ FILLPEN ] = 0;
}
data->dec_image = (struct Image *) NewObject( NULL, SYSICLASS,
SYSIA_Which, (fdm == FREEVERT) ? UPIMAGE : LEFTIMAGE,
SYSIA_DrawInfo, dri,
SYSIA_Size, size,
TAG_DONE );
data->inc_image = (struct Image *) NewObject( NULL, SYSICLASS,
SYSIA_Which, (fdm == FREEVERT) ? DOWNIMAGE : RIGHTIMAGE,
SYSIA_DrawInfo, dri,
SYSIA_Size, size,
TAG_DONE );
if( !( scr->Activation & GADGET_BORDER_FLAGS ) )
dri->dri_Pens[FILLPEN] = oldfill;
if( data->dec_image && data->inc_image )
{
data->prop = NewObject( NULL,PROPGCLASS,
PGA_Freedom, fdm,
PGA_NewLook, TRUE,
PGA_Borderless, TRUE,
PGA_Total, total,
PGA_Visible, visible,
PGA_Top, top,
ICA_TARGET, scr,
GA_ID, PROP_ID,
TAG_DONE );
data->decbtn = NewObject( AFBUTTON_GetClass(), NULL,
GA_Image, data->dec_image,
GA_ID, DECBTN_ID,
ICA_TARGET, scr,
TAG_DONE );
data->incbtn = NewObject( AFBUTTON_GetClass(), NULL,
GA_Image, data->inc_image,
GA_ID, INCBTN_ID,
ICA_TARGET, scr,
TAG_DONE );
if( data->prop && data->decbtn && data->incbtn )
{
position_gadgets( scr, data, fdm );
return (ULONG)scr;
}
}
DoMethod( (Object *) scr, OM_DISPOSE );
}
}
return 0L;
}
static ULONG
dispose_method( Class *cl, Object *o )
{
struct InstanceData *data = INST_DATA( cl, o );
if( data->prop ) { DisposeObject( (Object *) data->prop ); data->prop = NULL; }
if( data->incbtn ) { DisposeObject( (Object *) data->incbtn ); data->incbtn = NULL; }
if( data->decbtn ) { DisposeObject( (Object *) data->decbtn ); data->decbtn = NULL; }
if( data->inc_image ) { DisposeObject( (Object *) data->inc_image ); data->inc_image = NULL; }
if( data->dec_image ) { DisposeObject( (Object *) data->dec_image ); data->dec_image = NULL; }
DoSuperMethod( cl, o, OM_DISPOSE );
return 0L;
}
static ULONG
set_method( Class *cl, Object *o, struct opSet *msg )
{
struct Gadget *scr = (struct Gadget *) o;
struct InstanceData *data = (struct InstanceData *)INST_DATA(cl,o);
struct TagItem *attrs = msg->ops_AttrList;
Tag filter[] = { PGA_Top, PGA_Visible, PGA_Total, TAG_DONE };
ULONG freedom;
DoSuperMethodA( cl, o, (Msg) msg );
FilterTagItems( attrs, filter, TAGFILTER_AND );
DoMethodA( (Object *) data->prop, (Msg) msg );
freedom = (data->decbtn->LeftEdge == data->incbtn->LeftEdge) ? FREEVERT : FREEHORIZ;
position_gadgets( scr, data, freedom );
return 0L;
}
static ULONG
update_method( Class *cl, Object *o, Msg msg )
{
struct opUpdate *updin = (struct opUpdate *)msg;
struct InstanceData *data = (struct InstanceData *)INST_DATA(cl,o);
struct Gadget *scr = (struct Gadget *)o;
struct opUpdate upd;
struct TagItem tag[5];
ULONG id,top,newtop;
id = GetTagData(GA_ID,0,updin->opu_AttrList);
top = QuickGetAttr( data->prop, PGA_Top );
/* DoMethod((Object *)data->prop,OM_GET,PGA_Top,&top); */
/* An update message is used for both OM_SET and OM_NOTIFY
since the messages are so much alike. */
upd.MethodID = OM_SET;
upd.opu_AttrList = tag;
upd.opu_GInfo = updin->opu_GInfo;
upd.opu_Flags = updin->opu_Flags;
/*
Only enter this if its a button update and an interrim message
Problem: First update message must emulate the gadgetdown message
*/
if(id>0&&updin->opu_Flags&OPUF_INTERIM)
{
if( id==DECBTN_ID ) newtop = top-1;
if( id==INCBTN_ID ) newtop = top+1;
tag[0].ti_Tag = PGA_Top; tag[0].ti_Data = newtop;
tag[1].ti_Tag = TAG_DONE;
/* Prevent backwards overrun, forwards overrun is prevented
by propgadget */
if(newtop!=-1) DoMethodA((Object *)data->prop,(Msg)&upd);
/* Initial check to prevent notification messages in case of overrun */
top = QuickGetAttr( data->prop, PGA_Top );
/* DoMethod((Object *)data->prop,OM_GET,PGA_Top,&top); */
}
/* Only enter if interim message or message from propg */
if( updin->opu_Flags&OPUF_INTERIM || id == PROP_ID )
{
/* Prevent notification in case of overrun */
if( id != PROP_ID && top != newtop) return(0);
/* Notify */
/* upd.MethodID = OM_NOTIFY;
tag[0].ti_Tag = PGA_Top; tag[0].ti_Data = top;
tag[1].ti_Tag = GA_ID; tag[1].ti_Data = scr->GadgetID;
tag[2].ti_Tag = TAG_DONE;
DoMethodA(o,(Msg)&upd); */
NotifyAttrChanges( o, updin->opu_GInfo, updin->opu_Flags, PGA_Top, top, GA_ID, scr->GadgetID, TAG_DONE );
}
return 0L;
}
static ULONG
hittest_method( Class *cl, Object *o, Msg msg )
{
struct gpHitTest *test = (struct gpHitTest *)msg;
struct Gadget *scr = (struct Gadget *)o;
struct InstanceData *data = (struct InstanceData *)INST_DATA(cl,o);
WORD x = test->gpht_Mouse.X ,y = test->gpht_Mouse.Y;
if( hit_test_gadget( data->prop, scr, test->gpht_GInfo, x, y ) )
{
data->act = (Object *)data->prop;
return GMR_GADGETHIT;
}
if( hit_test_gadget( data->decbtn, scr, test->gpht_GInfo, x, y ) )
{
data->act = (Object *)data->decbtn;
return GMR_GADGETHIT;
}
if( hit_test_gadget( data->incbtn, scr, test->gpht_GInfo, x, y ) )
{
data->act = (Object *)data->incbtn;
return GMR_GADGETHIT;
}
return 0L;
}
static ULONG
goactive_method( Class *cl, Object *o, Msg msg )
{
struct InstanceData *data = (struct InstanceData *)INST_DATA(cl,o);
struct gpInput *in = (struct gpInput *)msg;
struct Gadget *act = (struct Gadget *)data->act, *scr = (struct Gadget *)o;
ULONG result;
in->gpi_Mouse.X -= act->LeftEdge-scr->LeftEdge;
in->gpi_Mouse.Y -= act->TopEdge-scr->TopEdge;
result = DoMethodA(data->act,msg);
return result;
}
static ULONG
handleinput_method( Class *cl, Object *o, Msg msg )
{
struct InstanceData *data = (struct InstanceData *)INST_DATA(cl,o);
struct gpInput *in = (struct gpInput *)msg;
struct Gadget *act = (struct Gadget *)data->act, *scr = (struct Gadget *)o;
ULONG result;
in->gpi_Mouse.X -= act->LeftEdge-scr->LeftEdge;
in->gpi_Mouse.Y -= act->TopEdge-scr->TopEdge;
result = DoMethodA(data->act,msg);
if(result)
{
if(scr->Activation&GACT_RELVERIFY)
{
result |= GMR_VERIFY;
*(in->gpi_Termination) = QuickGetAttr( data->prop, PGA_Top );
}
else
{
result &= ~GMR_VERIFY;
}
}
return result;
}
static ULONG
goinactive_method( Class *cl, Object *o, Msg msg )
{
struct InstanceData *data = (struct InstanceData *) INST_DATA( cl, o );
ULONG result;
result = DoMethodA(data->act,msg);
data->act = NULL;
return result;
}
static ULONG
render_method( Class *cl, Object *o, Msg msg )
{
struct gpRender *rend = (struct gpRender *)msg;
struct InstanceData *data = INST_DATA( cl, o );
DoMethodA( (Object *) data->prop,msg);
DoMethodA( (Object *) data->decbtn,msg);
DoMethodA( (Object *) data->incbtn,msg);
return 1L;
}
static ULONG
layout_method( Class *cl,Object *o, Msg msg )
{
struct gpLayout *lay = (struct gpLayout *)msg;
struct GadgetInfo *gi = lay->gpl_GInfo;
struct Gadget *scr = (struct Gadget *)o;
struct InstanceData *data = (struct InstanceData *)INST_DATA(cl,o);
if( scr->Flags & GFLG_RELWIDTH )
{
data->incbtn->LeftEdge = scr->LeftEdge + gi->gi_Domain.Width + scr->Width - data->incbtn->Width;
data->decbtn->LeftEdge = data->incbtn->LeftEdge - data->decbtn->Width;
}
if( scr->Flags & GFLG_RELHEIGHT )
{
data->incbtn->TopEdge = scr->TopEdge + gi->gi_Domain.Height + scr->Height - data->incbtn->Height;
data->decbtn->TopEdge = data->incbtn->TopEdge - data->decbtn->Height;
}
return 1L;
}
static VOID
position_gadgets( struct Gadget *scr, struct InstanceData *data, ULONG freedom )
{
UWORD x, y;
if( freedom == FREEVERT)
{
scr->Width = data->incbtn->Width;
x = 0;
y = data->decbtn->Height*2;
}
else
{
x = data->decbtn->Width*2;
scr->Height = data->decbtn->Height;
y = 0;
}
set_gadget_position( scr, data->prop, 4, 2 );
set_gadget_size( scr, data->prop, x+8, y+4 );
if(freedom == FREEVERT)
y = scr->Height - data->incbtn->Height;
else
x = scr->Width - data->incbtn->Width;
set_gadget_position( scr, data->incbtn, x, y );
if(freedom == FREEVERT)
y -= data->decbtn->Height;
else
x -= data->decbtn->Width;
set_gadget_position( scr, data->decbtn, x, y );
return;
}
static VOID
set_gadget_position( struct Gadget *source, struct Gadget *dest, UWORD x_offset, UWORD y_offset )
{
dest->LeftEdge = source->LeftEdge + x_offset;
dest->TopEdge = source->TopEdge + y_offset;
dest->Flags |= source->Flags & ( GFLG_RELRIGHT | GFLG_RELBOTTOM );
dest->Activation |= source->Activation & GADGET_BORDER_FLAGS;
return;
}
static VOID
set_gadget_size( struct Gadget *source, struct Gadget *dest, UWORD x_offset, UWORD y_offset )
{
dest->Width = source->Width - x_offset;
dest->Height = source->Height - y_offset;
dest->Flags |= ( source->Flags & ( GFLG_RELWIDTH | GFLG_RELHEIGHT ));
return;
}
static BOOL
hit_test_gadget( struct Gadget *gad, struct Gadget *rel_gad, struct GadgetInfo *gi, WORD x, WORD y )
{
UWORD gx = gad->LeftEdge - rel_gad->LeftEdge;
UWORD gy = gad->TopEdge - rel_gad->TopEdge;
UWORD gw = (gad->Flags & GFLG_RELWIDTH) ? gx + gi->gi_Domain.Width + gad->Width : gx + gad->Width;
UWORD gh = (gad->Flags & GFLG_RELHEIGHT) ? gy + gi->gi_Domain.Height + gad->Height : gy + gad->Height;
return ( x >= gx && x <= gw && y >= gy && y <= gh );
}